#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "cJSON.h"
#include "easyjs.h"

#define CFG_FILE_SYS "ktcfg_sys.json"
#define JS_MAX_SIZE (10*1024)

#define DEFUALT_BOARD_MODEL  0x10106003 /* 101-06-003*/
#define DEFUALT_SOFT_VERSION 0x30101 /* 301.01 = v3.01.01 */

char *default_js_str = "{\
	'uart_name':	'/dev/ttyS0',\
	'file_name':	'update.bin',\
	'uart_baud':	19200,\
	'uart_parity':	1,\
	'remote_uart_baud':	19200,\
	'remote_uart_parity':	1,\
	'o2p_low_val':	1900,\
	'o2p_lowc_val':	2050,\
	'o2p_pool_val':	2050,\
	'weiht_mainboard':	10000,\
	'weiht_fenzisai':	100,\
	'weiht_filter':	500,\
	'aswt_en':	0,\
	'aswt_a0':	65,\
	'aswt_a1':	65,\
	'aswt_a2':	65,\
	'aswt_a3':	60,\
	'aswt_a4':	60,\
	'bin_maigc':	269508611,\
	'bin_ver':	196865,\
	'c_air_p':	947,\
	'c_o1':	150,\
	'c_o2':	750,\
}";

char *default_js_str2 = "{\"uart_name\":	\"/dev/ttyS0\"}";


cJSON *js_syscfg = NULL;

/* 默认值 */
struct _usercfg usercfg = {\
    {"/dev/ttyS0"}, \
    {"update.bin"}, \
    19200,\
    1,\
    19200, /* 控制单元串口波特率 */ \
    1, /* 控制单元串口奇偶校验 */ \
    1900, /* 默认氧浓度低检测阈值 */ \
    2050, /* 默认氧浓度低恢复阈值*/ \
    2050, /* 默认分子筛效率低阈值 */ \
    10000, /* 主板工作维护时间（小时）  */ \
    100, /* 分子筛维护时间 */ \
    500, /* 过滤器维护时间 */ \
    0, /* 分子筛aswt使能 */ \
    {65, 65, 65, 60, 60}, /* 分子筛aswt_array */ \
    DEFUALT_BOARD_MODEL,\
    DEFUALT_SOFT_VERSION,\
    947,\
    150,\
    750,\
};

int parse_numb_u8(cJSON *f, char *item, uint8_t *val) {
    int ret = 0;
    if(f != NULL) {
        cJSON *s = cJSON_GetObjectItem(f, item);
        if(s != NULL) {
            double number = cJSON_GetNumberValue(s);
            *val = (uint8_t)number;
            ret = 1;
        }
    }
    return ret;
}

int parse_numb_u32(cJSON *f, char *item, uint32_t *val) {
    int ret = 0;
    if(f != NULL) {
        cJSON *s = cJSON_GetObjectItem(f, item);
        if(s != NULL) {
            double number = cJSON_GetNumberValue(s);
            *val = (uint32_t)number;
            ret = 1;
        }
    }
    return ret;
}

int parse_str(cJSON *f, char *item, char* val) {
    int ret = 0;
    if(f != NULL) {
        cJSON *s = cJSON_GetObjectItem(f, item);
        if(s != NULL) {
            char* src = cJSON_GetStringValue(s);
            if( NULL != strcpy(val, src)) {
                ret = 1;
            }
        }
    }
    return ret;
}

#define GET_NUM8(ITEM, p) parse_numb_u8(node, ITEM, (uint8_t*)p)
#define GET_NUM32(ITEM, p) parse_numb_u32(root, ITEM, (uint32_t*)p)
#define GET_STR(ITEM, p) parse_str(root, ITEM, (char*)p)

/* 反序列化 */
static int unserialize_cfg(char *text)
{
    cJSON *root = cJSON_Parse(text);
	if (!root) {
        printf("cJSON unserialize failed\n");
        return -1;
    }else {
        GET_STR("uart_name", &usercfg.uart_name);
        GET_STR("file_name", &usercfg.file_name);
        GET_NUM32("uart_baud", &usercfg.uart_baud);
        GET_NUM32("uart_parity", &usercfg.uart_parity);
        GET_NUM32("remote_uart_baud", &usercfg.remote_uart_baud);
        GET_NUM32("remote_uart_parity", &usercfg.remote_uart_parity);
        GET_NUM32("o2p_low_val", &usercfg.o2p_low_val);
        GET_NUM32("o2p_lowc_val", &usercfg.o2p_lowc_val);
        GET_NUM32("o2p_pool_val", &usercfg.o2p_pool_val);
        GET_NUM32("weiht_mainboard", &usercfg.weiht_mainboard);
        GET_NUM32("weiht_fenzisai", &usercfg.weiht_fenzisai);
        GET_NUM32("weiht_filter", &usercfg.weiht_filter);
        GET_NUM32("aswt_en", &usercfg.sova_swt_en);
        GET_NUM32("aswt_a0", &usercfg.sova_swt_array[0]);
        GET_NUM32("aswt_a1", &usercfg.sova_swt_array[1]);
        GET_NUM32("aswt_a2", &usercfg.sova_swt_array[2]);
        GET_NUM32("aswt_a3", &usercfg.sova_swt_array[3]);
        GET_NUM32("aswt_a4", &usercfg.sova_swt_array[4]);
        GET_NUM32("bin_maigc", &usercfg.bin_maigc);
        GET_NUM32("bin_ver", &usercfg.bin_ver);
        GET_NUM32("c_air_p", &usercfg.c_air_p);
        GET_NUM32("c_o1", &usercfg.c_o1);
        GET_NUM32("c_o2", &usercfg.c_o2);
	}
    printf("uart_name: %s baud: %d parity %d\r\n", usercfg.uart_name, usercfg.uart_baud, usercfg.uart_parity);
    printf("cfg bin file: %s magic: %08X version: %x.%02x\r\n", usercfg.file_name,\
         usercfg.bin_maigc, usercfg.bin_ver >> 8, usercfg.bin_ver&0xff);
    js_syscfg = root;
    return 0;
}

static int unserialize_file(const char* file_name)
{
    int ret = 0;
	FILE *f; long len; char *data;
	f = fopen(file_name, "rb");
    if(f == NULL) {
        return -1;
    }
	fseek(f, 0, SEEK_END);
	len = ftell(f);
    if(len <= 0) {
        return -2;
    }
	fseek(f, 0, SEEK_SET);
	data = (char*)malloc(len + 1);
	fread(data, 1, len, f);
	fclose(f);
    if( 0 == strcmp(file_name, CFG_FILE_SYS) ) {
        ret = unserialize_cfg(data);
    }
	free(data);
    return ret;
}

static int _json_save(const char* file_name, cJSON *root) {
    char *out = malloc(JS_MAX_SIZE);
    if (!cJSON_PrintPreallocated(root, out, JS_MAX_SIZE, 1)) {
        printf("cJSON Print failed!\n");
        return -1;
    }
    FILE* fp = fopen(file_name ,"w+");
	fprintf(fp, "%s", out);
	fclose(fp);
    free(out);
    return 0;
}

/* 序列初始化 */
static void _cfg_restore(void)
{
    cJSON *root = cJSON_CreateObject();
    if(root) {
        cJSON_AddStringToObject(root, "uart_name", usercfg.uart_name);
        cJSON_AddStringToObject(root, "file_name", usercfg.file_name);
        cJSON_AddNumberToObject(root, "uart_baud", usercfg.uart_baud);
        cJSON_AddNumberToObject(root, "uart_parity", usercfg.uart_parity);
        cJSON_AddNumberToObject(root, "remote_uart_baud", usercfg.remote_uart_baud);
        cJSON_AddNumberToObject(root, "remote_uart_parity", usercfg.remote_uart_parity);
        cJSON_AddNumberToObject(root, "o2p_low_val", usercfg.o2p_low_val);
        cJSON_AddNumberToObject(root, "o2p_lowc_val", usercfg.o2p_lowc_val);
        cJSON_AddNumberToObject(root, "o2p_pool_val", usercfg.o2p_pool_val);
        cJSON_AddNumberToObject(root, "weiht_mainboard", usercfg.weiht_mainboard);
        cJSON_AddNumberToObject(root, "weiht_fenzisai", usercfg.weiht_fenzisai);
        cJSON_AddNumberToObject(root, "weiht_filter", usercfg.weiht_filter);
        cJSON_AddNumberToObject(root, "aswt_en", usercfg.sova_swt_en);
        cJSON_AddNumberToObject(root, "aswt_a0", usercfg.sova_swt_array[0]);
        cJSON_AddNumberToObject(root, "aswt_a1", usercfg.sova_swt_array[1]);
        cJSON_AddNumberToObject(root, "aswt_a2", usercfg.sova_swt_array[2]);
        cJSON_AddNumberToObject(root, "aswt_a3", usercfg.sova_swt_array[3]);
        cJSON_AddNumberToObject(root, "aswt_a4", usercfg.sova_swt_array[4]);
        cJSON_AddNumberToObject(root, "bin_maigc", usercfg.bin_maigc);
        cJSON_AddNumberToObject(root, "bin_ver", usercfg.bin_ver);
        cJSON_AddNumberToObject(root, "c_air_p", usercfg.c_air_p);
        cJSON_AddNumberToObject(root, "c_o1", usercfg.c_o1);
        cJSON_AddNumberToObject(root, "c_o2", usercfg.c_o2);
        _json_save(CFG_FILE_SYS, root);
        js_syscfg = root;
    }
}


static uint8_t jscfg_wflg = 0;
static void _jscfg_set_intval(const char* item_name, int val) {
    cJSON *item = NULL;
    if(js_syscfg) {
        item = cJSON_GetObjectItem(js_syscfg, item_name);
        if(item) {
            cJSON_SetIntValue(item, val);
            jscfg_wflg = 1;
        }
    }
}

static void _jscfg_set_str(const char* item_name, const char* valstr) {
    cJSON *item = NULL;
    if(js_syscfg) {
        item = cJSON_GetObjectItem(js_syscfg, item_name);
        if(item) {
            cJSON_SetValuestring(item, valstr);
            jscfg_wflg = 1;
        }
    }
}

void jscfgset_uart_name(const char* uart_name) {
    if(strlen(uart_name) < 64) {
        strcpy(usercfg.uart_name, uart_name);
        _jscfg_set_str("uart_name", uart_name);
    }
}

void jscfgset_uart_baud(uint32_t boud) {
    usercfg.uart_baud = boud;
    _jscfg_set_intval("uart_baud", (int)boud);
}

void jscfgset_uart_parity(uint32_t parity) {
    usercfg.uart_parity = parity;
    _jscfg_set_intval("uart_parity", (int)parity);
}

void jscfgset_remote_uart_baud(uint32_t val) {
    usercfg.remote_uart_baud = val;
    _jscfg_set_intval("remote_uart_baud", (int)val);
}

void jscfgset_remote_uart_parity(uint32_t val) {
    usercfg.remote_uart_parity = val;
    _jscfg_set_intval("remote_uart_parity", (int)val);
}

void jscfgset_o2p_low_val(uint32_t val) {
    usercfg.o2p_low_val = val;
    _jscfg_set_intval("o2p_low_val", (int)val);
}

void jscfgset_o2p_lowc_val(uint32_t val) {
    usercfg.o2p_lowc_val = val;
    _jscfg_set_intval("o2p_lowc_val", (int)val);
}

void jscfgset_o2p_pool_val(uint32_t val) {
    usercfg.o2p_pool_val = val;
    _jscfg_set_intval("o2p_pool_val", (int)val);
}

void jscfgset_weiht_mainboard(uint32_t val) {
    usercfg.weiht_mainboard = val;
    _jscfg_set_intval("weiht_mainboard", (int)val);
}

void jscfgset_weiht_fenzisai(uint32_t val) {
    usercfg.weiht_fenzisai = val;
    _jscfg_set_intval("weiht_fenzisai", (int)val);
}

void jscfgset_weiht_filter(uint32_t val) {
    usercfg.weiht_filter = val;
    _jscfg_set_intval("weiht_filter", (int)val);
}

void jscfgset_aswt_en(uint32_t val) {
    usercfg.sova_swt_en = val;
    _jscfg_set_intval("aswt_en", (int)val);
}

void jscfgset_aswt_array(uint32_t *array, uint32_t len) {
    if(5 == len) {
        memcpy( &usercfg.sova_swt_array[0], array, 5*sizeof(uint32_t) );
        _jscfg_set_intval("aswt_a0", (int)array[0]);
        _jscfg_set_intval("aswt_a1", (int)array[1]);
        _jscfg_set_intval("aswt_a2", (int)array[2]);
        _jscfg_set_intval("aswt_a3", (int)array[3]);
        _jscfg_set_intval("aswt_a4", (int)array[4]);
    }
}

void jscfgset_c_air_p(uint32_t val) {
    usercfg.c_air_p = val;
    _jscfg_set_intval("c_air_p", (int)val);
}

void jscfgset_c_o1(uint32_t val) {
    usercfg.c_o1 = val;
    _jscfg_set_intval("c_o1", (int)val);
}

void jscfgset_c_o2(uint32_t val) {
    usercfg.c_o2 = val;
    _jscfg_set_intval("c_o2", (int)val);
}

void jscfg_write_loop(void) {
    if(jscfg_wflg ) {
        _json_save(CFG_FILE_SYS, js_syscfg);
        jscfg_wflg = 0;
    }
}



/* 序列初始化 */
static void test2(void)
{
    cJSON *root = cJSON_CreateObject();
    if(root) {
        cJSON_AddStringToObject(root, "uart_name", usercfg.uart_name);
        cJSON_AddStringToObject(root, "file_name", usercfg.file_name);
        cJSON_AddNumberToObject(root, "uart_baud", usercfg.uart_baud);
        cJSON_AddNumberToObject(root, "uart_parity", usercfg.uart_parity);
        cJSON_AddNumberToObject(root, "remote_uart_baud", usercfg.remote_uart_baud);
        cJSON_AddNumberToObject(root, "remote_uart_parity", usercfg.remote_uart_parity);
        cJSON_AddNumberToObject(root, "o2p_low_val", usercfg.o2p_low_val);
        cJSON_AddNumberToObject(root, "o2p_lowc_val", usercfg.o2p_lowc_val);
        cJSON_AddNumberToObject(root, "o2p_pool_val", usercfg.o2p_pool_val);
        cJSON_AddNumberToObject(root, "weiht_mainboard", usercfg.weiht_mainboard);
        cJSON_AddNumberToObject(root, "weiht_fenzisai", usercfg.weiht_fenzisai);
        cJSON_AddNumberToObject(root, "weiht_filter", usercfg.weiht_filter);
        cJSON_AddNumberToObject(root, "aswt_en", usercfg.sova_swt_en);
        cJSON_AddNumberToObject(root, "aswt_a0", usercfg.sova_swt_array[0]);
        cJSON_AddNumberToObject(root, "aswt_a1", usercfg.sova_swt_array[1]);
        cJSON_AddNumberToObject(root, "aswt_a2", usercfg.sova_swt_array[2]);
        cJSON_AddNumberToObject(root, "aswt_a3", usercfg.sova_swt_array[3]);
        cJSON_AddNumberToObject(root, "aswt_a4", usercfg.sova_swt_array[4]);
        cJSON_AddNumberToObject(root, "bin_maigc", usercfg.bin_maigc);
        cJSON_AddNumberToObject(root, "bin_ver", usercfg.bin_ver);
        cJSON_AddNumberToObject(root, "c_air_p", usercfg.c_air_p);
        cJSON_AddNumberToObject(root, "c_o1", usercfg.c_o1);
        cJSON_AddNumberToObject(root, "c_o2", usercfg.c_o2);

        char *out = malloc(JS_MAX_SIZE);
        if (!cJSON_PrintPreallocated(root, out, 1024, 1)) {
            printf("cJSON Print failed!\n");
            return ;
        }
        printf("cJSON Print ok!\n");
    }
}

void CJSON_CDECL json_cfg_init(void) {
    printf("str 1: %s\n", default_js_str);
    unserialize_cfg(default_js_str);
    
    printf("str 2: %s\n", default_js_str2);
    unserialize_cfg(default_js_str2);
    test2();
}


